/*
 * Copyright (c) 2009, Hamish Morgan. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the University of Sussex nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package locusts.server.physics;

import locusts.common.entities.*;
import locusts.lib.MathUtil;

/**
 * Implementation of the <em>Rotate 'N' Translate</em> mechanism for
 * integrated control of rotation and translation using a contact.
 *
 * See: http://innovis.cpsc.ucalgary.ca/Research/RotationNTranslation
 * 
 * [1] Mark S. Hancock, Frederic D. Vernier, Daniel Wigdor, Sheelagh
 * Carpendale and Chia Shen. Rotation and Translation Mechanisms for Tabletop
 * Interaction. In TableTop2006: Proceedings of IEEE International Workshop
 * on Horizontal Interactive Human-Computer Systems. IEEE Computer Society,
 * pages 79-86, 2006.
 *
 * [2] Russell Kruger, M. Sheelagh T. Carpendale, Stacey D. Scott and Anthony
 * Tang. Fluid Integration of Rotation and Translation. In CHI '05:
 * Proceedings of the SIGCHI Conference on Human Factors in Computing Systems.
 * ACM Press, pages 601-610, 2005.
 *
 * 
 * @author Hamish Morgan
 */
public class RNTJoint extends TranslateJoint {

    private static final double MIN_DISTANCE = 1f;

    public RNTJoint(Entity A, Entity B, double ax, double ay, double bx,
            double by) {
        super(A, B, ax, ay, bx, by);
    }

    public RNTJoint(Entity a, Entity b, double x, double y) {
        super(a, b, x, y);
    }

    public RNTJoint(Entity a, Entity b) {
        super(a, b);
    }

    protected RNTJoint(RNTJoint other) {
        super(other);
    }

    @Override
    public void update(double period) {

        // that point of contact for moving
        final double Ox = A.getX() + Ax;
        final double Oy = A.getY() + Ay;

        // the target for the point of contact
        final double Tx = B.getX() + Bx;
        final double Ty = B.getY() + By;

        // If it hasn't moved much then don't bother.
        final double dx = Tx - Ox;
        final double dy = Ty - Oy;
        if (dx * dx + dy * dy <= MIN_DISTANCE * MIN_DISTANCE)
            return;

        // the center of the object to be moved
        final double Cx = A.getX();
        final double Cy = A.getY();


        // The angle OCT that will be used to rotate the object
        final double theta = MathUtil.angleBetween(
                Tx - Cx, Ty - Cy, Ox - Cx, Oy - Cy);

        // Rotate the center C around O and translate by OT
        final double x = Cx - Ox;
        final double y = Cy - Oy;
        final double Cxi = Math.cos(theta) * x - Math.sin(theta) * y + Tx;
        final double Cyi = Math.sin(theta) * x + Math.cos(theta) * y + Ty;


        // Update the position and orientation of Entity A
        A.setX(Cxi);
        A.setY(Cyi);
        A.setOrientation(A.getOrientation() + theta);

        // Update the offset of the drag point to T
        Ax = Tx - Cxi;
        Ay = Ty - Cyi;

        // Notify that this object has been changed and will need to be sent
        // to clients.
        A.setModified();
    }

    @Override
    public RNTJoint clone() {
        return new RNTJoint(this);
    }
}
